﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

using SharedGenomics.Workbench.Core;
using SharedGenomics.Core;
using SharedGenomics.Domain;

namespace SharedGenomics.Workbench.Services
{
    public class BITSFileUpload : IFileUpload
    {
        public BITSFileUpload(ILoginManager loginManager)
        {
            this.LoginManager = loginManager;
        }

        public void UploadFile(string localFilePath, Uri remoteFileUri)
        {
            localFilePath.ThrowIfNull("localFileUri");
            remoteFileUri.ThrowIfNull("remoteFileUri");

            BitsInterop.IBackgroundCopyJob job;
            BitsInterop.IBackgroundCopyJob2 job2;
            Guid jobGuid;

            BitsInterop.IBackgroundCopyManager manager = (BitsInterop.IBackgroundCopyManager)new BitsInterop.BackgroundCopyManager();
            BitsInterop.JobType jt = BitsInterop.JobType.Upload;
            manager.CreateJob("My Upload", jt, out jobGuid, out job);

            //The IBackgroundCopyJob interface has been updated to IBackgroundCopyJob2 with some new methods so, to use these new methods, 
            //we perform a cast (which does a COM QueryInterface underneath to get an IBackgroundCopyJob2 interface reference from 
            //IBackgroundCopyJob)
            job2 = (BitsInterop.IBackgroundCopyJob2)job;

            //register for notification if the job fails
            job2.SetNotifyFlags(BitsInterop.BG_JOB_NOTIFICATION_TYPE.BG_NOTIFY_JOB_ERROR);
            //job2.SetNotifyInterface(new BITSJobNotification(this.AppController));

            job2.SetNoProgressTimeout(30);

            //apply the user credentials to the job
            this.ApplyUserCredentialsToBITSJob(this.LoginManager.LoginCredentials, job2);

            //assign file name in destination uri and add file to job
            job2.AddFile(remoteFileUri.ToString(), localFilePath);

            //Start the upload
            job2.Resume();
        }

        private void ApplyUserCredentialsToBITSJob(UserCredentials credentials, BitsInterop.IBackgroundCopyJob2 job)
        {
            BitsInterop.BG_AUTH_CREDENTIALS cred = new BitsInterop.BG_AUTH_CREDENTIALS();

            cred.Scheme = BitsInterop.BG_AUTH_SCHEME.BG_AUTH_SCHEME_NTLM;
            cred.Target = BitsInterop.BG_AUTH_TARGET.BG_AUTH_TARGET_SERVER;

            //Get username and password stored on Parent form.
            cred.Credentials.Basic.UserName = String.Format("{0}\\{1}", credentials.Domain, credentials.UserName);    //use domain\account format

            //get the password from the secure string - make sure the resulting managed string is cleared after use (although since it hangs around in 
            //plain text in the BITS credential object anyway...)
            IntPtr ptr = Marshal.SecureStringToBSTR(credentials.Password);

            try
            {
                cred.Credentials.Basic.Password = Marshal.PtrToStringAuto(ptr);
            }
            finally
            {
                Marshal.ZeroFreeBSTR(ptr);
            }

            job.SetCredentials(ref cred);
        }

        private ILoginManager LoginManager { get; set; }
    }
}
